﻿Imports System
Imports System.Runtime.InteropServices

Namespace System.Workflow.ComponentModel.Compiler
    Friend NotInheritable Class PDBReader
        Implements IDisposable
        ' Methods
        Public Sub New(ByVal assemblyPath As String)
            Dim unknown As Object = Nothing
            Dim o As IMetaDataDispenser = Nothing
            Try 
                Dim riid As New Guid("7DAC8207-D3AE-4c75-9B67-92801A497D44")
                o = DirectCast(New MetaDataDispenser, IMetaDataDispenser)
                o.OpenScope(assemblyPath, 0, (riid), unknown)
                Me.symReader = DirectCast(New CorSymReader_SxS, ISymUnmanagedReader)
                Me.symReader.Initialize(unknown, assemblyPath, Nothing, Nothing)
            Finally
                If (Not unknown Is Nothing) Then
                    Marshal.ReleaseComObject(unknown)
                End If
                If (Not o Is Nothing) Then
                    Marshal.ReleaseComObject(o)
                End If
            End Try
        End Sub

        Private Sub Dispose()
            If (Not Me.symReader Is Nothing) Then
                Marshal.ReleaseComObject(Me.symReader)
                Me.symReader = Nothing
            End If
        End Sub

        Protected Overrides Sub Finalize()
            Try 
                Me.Dispose
            Finally
                MyBase.Finalize
            End Try
        End Sub

        Public Sub GetSourceLocationForOffset(ByVal methodDef As UInt32, ByVal offset As UInt32, <Out> ByRef fileLocation As String, <Out> ByRef line As UInt32, <Out> ByRef column As UInt32)
            fileLocation = Nothing
            line = 0
            column = 0
            Dim o As ISymUnmanagedMethod = Nothing
            Dim documents As ISymUnmanagedDocument() = Nothing
            Dim pointsCount As UInt32 = 0
            Try 
                o = Me.symReader.GetMethod(methodDef)
                pointsCount = o.GetSequencePointCount
                documents = New ISymUnmanagedDocument(pointsCount  - 1) {}
                Dim offsets As UInt32() = New UInt32(pointsCount  - 1) {}
                Dim lines As UInt32() = New UInt32(pointsCount  - 1) {}
                Dim columns As UInt32() = New UInt32(pointsCount  - 1) {}
                Dim endLines As UInt32() = New UInt32(pointsCount  - 1) {}
                Dim endColumns As UInt32() = New UInt32(pointsCount  - 1) {}
                o.GetSequencePoints(pointsCount, pointsCount, offsets, documents, lines, columns, endLines, endColumns)
                Dim index As UInt32 = 1
                Do While (index < pointsCount)
                    If (offsets(index) > offset) Then
                        Exit Do
                    End If
                    index += 1
                Loop
                index -= 1
                Do While ((columns(index) = 0) AndAlso (index > 0))
                    index -= 1
                Loop
                Do While ((index < pointsCount) AndAlso (columns(index) = 0))
                    index += 1
                Loop
                If ((index >= pointsCount) OrElse (columns(index) = 0)) Then
                    index = 0
                End If
                line = lines(index)
                column = columns(index)
                Dim document As ISymUnmanagedDocument = documents(index)
                Dim urlLength As UInt32 = &H105
                Dim url As New String(ChrW(0), CInt(urlLength))
                document.GetURL(urlLength, urlLength, url)
                fileLocation = url.Substring(0, (CInt(urlLength) - 1))
            Finally
                Dim i As UInt32
                For i = 0 To pointsCount - 1
                    If (Not documents(i) Is Nothing) Then
                        Marshal.ReleaseComObject(documents(i))
                    End If
                Next i
                If (Not o Is Nothing) Then
                    Marshal.ReleaseComObject(o)
                End If
            End Try
        End Sub

        Private Sub System.IDisposable.Dispose() Implements IDisposable.Dispose
            Me.Dispose
            GC.SuppressFinalize(Me)
        End Sub


        ' Fields
        Private Const IMetaDataImportGuid As String = "7DAC8207-D3AE-4c75-9B67-92801A497D44"
        Private symReader As ISymUnmanagedReader
    End Class
End Namespace

